package com.carrental.api.common.aop;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.carrental.common.response.CommonResult;
import com.carrental.common.exception.OperationException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;

/**
 * 错误结果处理切面(全局controller)
 *
 * @author 梁毅
 */
@Slf4j
@Aspect
@Component
@Order(5)
public class PlmBindingResultAspect {

    private static final String SERVICE_RESULT_DATA_POINT = "execution(public * com.carrental.api.*.service.impl.*.*(..))";

    private static final String CONTROLLER_RESULT_DATA_POINT = "execution(public * com.carrental.api.*.controller.*.*(..))";

    @Pointcut(value = CONTROLLER_RESULT_DATA_POINT)
    public void bindingResult() {
        System.out.println("进来AOP啦！");
    }


    /**
     * //这里 目前只是全局去除bigDecimal后面无效的0
     * 后置返回通知
     * 这里需要注意的是:
     * 如果参数中的第一个参数为JoinPoint，则第二个参数为返回值的信息
     * 如果参数中的第一个参数不为JoinPoint，则第一个参数为returning中对应的参数
     * returning 限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知，否则不执行，对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
     */
    @AfterReturning(value = SERVICE_RESULT_DATA_POINT, returning = "keys")
    public void doAfterReturningAdvice1(JoinPoint joinPoint, Object keys) throws IllegalAccessException {
        if (keys instanceof Page) {
            Page<?> page = (Page<?>) keys;
            for (Object entity : page.getRecords()) {
                Field[] fields = entity.getClass().getDeclaredFields();
                for (Field field : fields) {
                    //成员变量为private,故必须进行此操做
                    field.setAccessible(true);
                    //修改前的值
                    Object fieldValue = field.get(entity);
                    if (fieldValue == null) {
                        continue;
                    }
                    if (!(fieldValue instanceof BigDecimal)) {
                        continue;
                    }
                    //核心代码：去除搜参数前后无效空字符
                    BigDecimal afterValue = ((BigDecimal) fieldValue).stripTrailingZeros();
                    field.set(entity, afterValue);
                }
            }
        } else if (keys instanceof List) {
            List<?> list = (List<?>) keys;
            for (Object entity : list) {
                Field[] fields = entity.getClass().getDeclaredFields();
                for (Field field : fields) {
                    //成员变量为private,故必须进行此操做
                    field.setAccessible(true);
                    //修改前的值
                    Object fieldValue = field.get(entity);
                    if (fieldValue == null) {
                        continue;
                    }
                    if (!(fieldValue instanceof BigDecimal)) {
                        continue;
                    }
                    //核心代码：去除搜参数前后无效空字符
                    BigDecimal afterValue = ((BigDecimal) fieldValue).stripTrailingZeros();
                    field.set(entity, afterValue);
                }
            }
        } else if (keys != null) {
            Field[] fields = keys.getClass().getDeclaredFields();
            for (Field field : fields) {
                //成员变量为private,故必须进行此操做
                field.setAccessible(true);
                //修改前的值
                Object fieldValue = field.get(keys);
                if (fieldValue == null) {
                    continue;
                }
                if (!(fieldValue instanceof BigDecimal)) {
                    continue;
                }
                //核心代码：去除搜参数前后无效空字符
                BigDecimal afterValue = ((BigDecimal) fieldValue).stripTrailingZeros();
                field.set(keys, afterValue);
            }
        }
    }


    /**
     * @param joinPoint ProceedingJoinPoint
     * @return Object
     * @throws Throwable Throwable
     * @author 梁毅
     */
    @Around("bindingResult()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget().getClass().getName();
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof BindingResult) {
                BindingResult result = (BindingResult) arg;
                if (result.hasErrors()) {
                    FieldError fieldError = result.getFieldError();
                    if (fieldError != null) {
                        return CommonResult.validateFailed(fieldError.getDefaultMessage());
                    } else {
                        return CommonResult.validateFailed();
                    }
                }
            }
        }

        System.out.println("进来AOP啦！");
        try {
            return joinPoint.proceed();
        } catch (OperationException e) {
            log.error("请求失败!:" + e.getMessage());
            return new CommonResult<OperationException>(e.getCode(), e.getMessage(), null);
        } catch (Exception e) {
            log.error("请求失败!:" + e.getMessage());
            return new CommonResult<OperationException>(500L, e.getMessage(), null);
        }
    }
}
